import Cesium from '../Ces/Cesium'
import WeDisplayShaders from './WeDisplayShaders';
import WeUniform from './WeUniform'

class WeDisplayEffectIcon {
  _weUniform: WeUniform
  static url = ''
  static iconLoading = false
  static iconImage
  defaultTexture
  _iconTexture
  _contextTexture: any
  _valid: boolean = false
  constructor() {
    const floatUniform = {
      repeatFactor: 4.0,
      atalsR: 6.0,
      atalsC: 7.0,
      atalsN: 20.0,
      iconBlendValue: 1.0,
    }

    this._weUniform = new WeUniform({ floatUniform, name: 'WeDisplayEffectIcon' });
  }

  set repeatFactor(value) {
    this._weUniform.Properties.repeatFactor = value
  }

  get repeatFactor() {
    return this._weUniform.Properties.repeatFactor
  }

  set iconBlendValue(value) {
    this._weUniform.Properties.iconBlendValue = value
  }

  get iconBlendValue() {
    return this._weUniform.Properties.iconBlendValue
  }

  setupUniform(uniforms) {
    if (!this.valid) return
    this._weUniform.setupUniform(uniforms)
    uniforms.u_IconTexture = this.texture
  }

  get valid() {
    return this._valid || (Cesium.defined(WeDisplayEffectIcon.url) && WeDisplayEffectIcon.url !== '')
  }

  get texture() {
    return this._contextTexture || this._iconTexture || this.defaultTexture
  }

  get samplerDeclare() {
    return this.valid ? 'uniform sampler2D u_IconTexture;' : ''
  }

  pushDefines(defines) {
    if (this.valid)
      defines.push(WeDisplayShaders.WeDefineHasICON)
  }

  get shaderSource() {
    return this.valid ? `
        ${this._weUniform.getSource(false)}
        precision highp float;

        float angleBetweenVectors(vec2 v1, vec2 v2) {
            float dotProduct = dot(normalize(v1), normalize(v2));
            float angle = acos(clamp(dotProduct, -1.0, 1.0));
            return angle;
        }
#ifdef IS_SAMPLER3D
        vec4 WeIcon(vec3 uv)
#else
        vec4 WeIcon(vec2 uv)
#endif
        {
            bool shouldFlipY = Weget_shouldFlipY() > 0.0;
            if(!shouldFlipY){
                uv.y = 1.0 - uv.y;
            }
            vec4 color = vec4(0.0);
            bool isUV = Weget_isUV() > 0.0;
            if(isUV){
                float minValue = Weget_minValue();
                float maxValue = Weget_maxValue();
                float atalsC = Weget_atalsC();
                float atalsR = Weget_atalsR();
                float atalsN = Weget_atalsN();
                float iconBlendValue = Weget_iconBlendValue();

                float repeatFactor = Weget_repeatFactor();
                vec2 repeat = floor(u_textureResolution / repeatFactor);
                vec2 st = uv.xy;
                vec2 iconUV = fract(st * repeat);
                vec2 iconID = floor(st * repeat);
                iconID /= repeat;

                if(!shouldFlipY){
                    iconID.y = 1.0 - iconID.y;
                }

                vec3 velocity = WeDecodeComponent(iconID).xyz;

                float numC = atalsC;
                float numR = atalsR;
                float maxLevel = atalsN;
                float value = length(velocity);
                float i = (value - minValue) / (maxValue - minValue);

                // 2m per level
                float iconIndex = ceil(value / 2.0);
                if(iconIndex > maxLevel){
                    iconIndex = maxLevel;
                }

                float localR = floor(iconIndex / numC);
                float localC = floor(mod(iconIndex,numC));
                float rad = angleBetweenVectors(velocity.xy,vec2(0.0,1.0));
                if(velocity.x < 0.0){
                    rad = czm_twoPi - rad;
                }
                float cosA = cos(rad);
                float sinA = sin(rad);
                iconUV -= vec2(0.5);
                mat2 rotMat = mat2(cosA, -sinA, sinA, cosA);
                iconUV = rotMat * iconUV;
                iconUV += vec2(0.5);

                iconUV /= vec2(numC,numR);
                iconUV += vec2(localC,localR) * (1.0 / vec2(numC,numR));
                iconUV = fract(iconUV);

                color = texture(u_IconTexture,iconUV);
                float r = 1.0 - clamp(i * 3.0,0.0,1.0);
                color.a *= clamp(i,iconBlendValue,1.0);

                if(length(velocity) == 0.0){
                    color.a = 0.0;
                }

                // debug
                // color = vec4(iconUV,0.0,1.0);
            }

            return color;
        }
        ` : ''
  }

  update(frameState) {
    const context = frameState.context

    if (!this.defaultTexture) {
      this.defaultTexture = context.defaultTexture
    }

    if (!frameState.passes.render
      || !this.valid
      || this._iconTexture
      || WeDisplayEffectIcon.iconLoading
    ) return


    if (context.iconTexture && !context.iconTexture.isDestroyed()) {
      this._iconTexture = context.iconTexture
      this._iconTexture.ref_count++
      return
    }

    if (WeDisplayEffectIcon.iconImage) {
      context.iconTexture = new Cesium.Texture({
        context,
        source: WeDisplayEffectIcon.iconImage,
        flipY: false,
      })
      context.iconTexture.ref_count = 0
    } else {
      WeDisplayEffectIcon.iconLoading = true
      Cesium.Resource.fetchImage(WeDisplayEffectIcon.url).then((image) => {
        WeDisplayEffectIcon.iconImage = image
        WeDisplayEffectIcon.iconLoading = false
      })
    }
  }

  isDestroyed() {
    return false
  }

  destroy() {
    if (this._iconTexture) {
      this._iconTexture.ref_count--
      if (this._iconTexture.ref_count === 0) {
        this._iconTexture = this._iconTexture.destroy()
        console.log('destroy WeDisplayEffectIcon.iconTexture')
      }
    }
    return Cesium.destroyObject(this)
  }
}

export default WeDisplayEffectIcon
